export default class WxRequest {
  defaults = {
    baseURL: '',
    url: '',
    data: null,
    method: 'GET',
    header: {
      'Content-type': 'application/json'
    },
    timeout: 60000,
    isLoading: true
  }

  interceptors = {
    request: (config) => config,
    response: (response) => response
  }

  queue = []

  constructor(params = {}) {
    this.defaults = Object.assign({}, this.defaults, params)
  }

  handleSuccess(res, options) {
    try {
      res.data = JSON.parse(res.data)
    } catch (e) {
      // do nothing
    }
    const mergeRes = Object.assign({}, res, {
      config: options,
      isSuccess: true
    })
    return this.interceptors.response(mergeRes)
  }

  handleFail(err, options) {
    const mergeErr = Object.assign({}, err, {
      config: options,
      isSuccess: false
    })
    return this.interceptors.response(mergeErr)
  }

  request(options) {
    this.timerId && clearTimeout(this.timerId)

    options.url = this.defaults.baseURL + options.url
    options = { ...this.defaults, ...options }
    options = this.interceptors.request(options)

    if (options.isLoading) {
      this.queue.length === 0 && wx.showLoading()
      this.queue.push('request')
    }

    return new Promise((resolve, reject) => {
      const commonOptions = {
        ...options,
        success: (res) => resolve(this.handleSuccess.call(this, res, options)),
        fail: (err) => reject(this.handleFail.call(this, err, options))
      }

      if (options.method === 'UPLOAD') {
        wx.uploadFile(commonOptions)
      } else {
        commonOptions.complete = () => {
          if (!options.isLoading) return

          this.queue.pop()
          this.queue.length === 0 && this.queue.push('request')

          this.timerId = setTimeout(() => {
            this.queue.pop()
            this.queue.length === 0 && wx.hideLoading()
          }, 100)
        }
        wx.request(commonOptions)
      }
    })
  }

  get(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'GET' }, config))
  }

  post(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'POST' }, config))
  }

  put(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'PUT' }, config))
  }

  delete(url, data = {}, config = {}) {
    return this.request(Object.assign({ url, data, method: 'DELETE' }, config))
  }

  upload(url, filePath, name = 'file', config = {}) {
    return this.request(Object.assign({ url, filePath, name, method: 'UPLOAD' }, config))
  }

  all(...promise) {
    return Promise.all(promise)
  }
}
